﻿using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace SportsPlatform.Jwt
{
    /// <summary>
    /// 
    /// </summary>
    public class JwtHelper
    {
        /// <summary>
        /// 颁发JWT字符串
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string IssueJwt(TokenModelJwt tokenModel)
        {
            string iss = AppSettingsHelper.Configuration["Jwt:Issuer"];
            string aud = AppSettingsHelper.Configuration["Jwt:Aud"];
            string secret = AppSettingsHelper.Configuration["Jwt:Key"];

            //var claims = new Claim[] //old
            var claims = new List<Claim>
                {
                 /*
                 * 特别重要：
                   1、这里将用户的部分信息，比如 uid 存到了Claim 中，如果你想知道如何在其他地方将这个 uid从 Token 中取出来，请看下边的SerializeJwt() 方法，或者在整个解决方案，搜索这个方法，看哪里使用了！
                   2、你也可以研究下 HttpContext.User.Claims ，具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                 */

                new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                //这个就是过期时间，目前是过期1000秒，可自定义，注意JWT有自己的缓冲过期时间
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(10000)).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Iss,iss),
                new Claim(JwtRegisteredClaimNames.Aud,aud),
                new Claim(ClaimTypes.Sid,tokenModel.CompanyId.ToString()),
                //new Claim(ClaimTypes.Role,tokenModel.Role),//为了解决一个用户多个角色(比如：Admin,System)，用下边的方法
               };

            // 可以将一个用户的多个角色全部赋予；
            //claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

            //秘钥 (SymmetricSecurityKey 对安全性的要求，密钥的长度太短会报出异常)
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: iss,
                claims: claims,
                signingCredentials: creds);

            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

        /// <summary>
        /// 解析
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static TokenModelJwt SerializeJwt(string jwtStr)
        {
             TokenModelJwt tokenModelJwt = new TokenModelJwt();
            if (string.IsNullOrEmpty(jwtStr) || jwtStr.ToUpper().Equals("NULL"))
            {
                tokenModelJwt.Code = SerializeJwtCode.Invalid;
                tokenModelJwt.Message = "ToKen未传入！";
                return tokenModelJwt;
            }
            try {
                var jwtHandler = new JwtSecurityTokenHandler();
                JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
                //object role;
                //try
                //{
                //    jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
                //}
                //catch (Exception e)
                //{
                //    Console.WriteLine(e);
                //    throw;
                //}
                object uid;
                object companyid;
                object logintime;
                object endtime;
                try
                {
                    jwtToken.Payload.TryGetValue(JwtRegisteredClaimNames.Jti, out uid);
                    jwtToken.Payload.TryGetValue(ClaimTypes.Sid, out companyid);
                    jwtToken.Payload.TryGetValue(JwtRegisteredClaimNames.Iat, out logintime);
                    jwtToken.Payload.TryGetValue(JwtRegisteredClaimNames.Exp, out endtime);
                    //判断是否过期
                    if (uid != null && endtime != null)
                    {
                        DateTime starttime = DateTimeOffset.FromUnixTimeSeconds(long.Parse(logintime.ToString())).DateTime.AddHours(8);
                        DateTime endtime1 = DateTimeOffset.FromUnixTimeSeconds(long.Parse(endtime.ToString())).DateTime.AddHours(8);
                        if (DateTime.Now > endtime1)
                        {
                            tokenModelJwt.Code = SerializeJwtCode.Overdue;
                            tokenModelJwt.Message = "ToKen已过期，请重新登录获取！";
                            return tokenModelJwt;
                        }
                    }
                    else {
                        tokenModelJwt.Code = SerializeJwtCode.Invalid;
                        tokenModelJwt.Message = "解析参数不全！";
                        return tokenModelJwt;
                    }
                }
                catch (Exception e)
                {
                    tokenModelJwt.Code = SerializeJwtCode.Abnormal;
                    tokenModelJwt.Message = e.Message.ToString();
                    return tokenModelJwt;
                }
                tokenModelJwt.Uid = new Guid(uid.ToString());
                tokenModelJwt.Code= SerializeJwtCode.Success;
                tokenModelJwt.CompanyId = companyid != null && !string.IsNullOrEmpty(companyid.ToString()) ? (new Guid(companyid.ToString()) == Guid.Empty ? null : new Guid(companyid.ToString())) : null;
                //tokenModelJwt.Role = role != null ? role.ToString() : "";

            }
            catch(Exception e) {
                tokenModelJwt.Code = SerializeJwtCode.Abnormal;
                tokenModelJwt.Message = e.Message.ToString();
            }
            return tokenModelJwt;
        }
    }

    

    /// <summary>
    /// 令牌
    /// </summary>
    public class TokenModelJwt
    {
        /// <summary>
        /// 状态码 1 有效，2无效，3过期，4解析异常
        /// </summary>
        public int Code { get; set; }

        /// <summary>
        /// Id
        /// </summary>
        public Guid Uid { get; set; }

        /// <summary>
        /// 公司Id,所属商户Id
        /// </summary>
        public Guid? CompanyId { get; set; }

        /// <summary>
        /// 角色
        /// </summary>
        public string Role { get; set; }

        /// <summary>
        /// 错误信息
        /// </summary>
        public string Message { get; set; }


    }

    /// <summary>
    /// 解析返回状态码
    /// </summary>
    public static class SerializeJwtCode {
        /// <summary>
        /// 有效
        /// </summary>
        public const int Success = 1;

        /// <summary>
        /// 无效
        /// </summary>
        public const int Invalid = 2;

        /// <summary>
        /// 过期
        /// </summary>
        public const int Overdue = 3;

        /// <summary>
        /// 异常
        /// </summary>
        public const int Abnormal = 4;
    }

    /// <summary>
    ///  appsettign.json 操作类
    /// </summary>
    public class AppSettingsHelper
    {
        /// <summary>
        ///
        /// </summary>
        public static IConfiguration Configuration { get; set; }

        static AppSettingsHelper()
        {
            //ReloadOnChange = true 当appsettings.json被修改时重新加载
            Configuration = new ConfigurationBuilder()
            .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true })
            .Build();
        }
    }
}
